// Logging.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#include "Logging.h"
#include "RegistryFacade.h"
#include <time.h>
#include <sys/timeb.h>
#include <comdef.h>
#include <iostream>
#include <sstream>

#ifdef _MANAGED
#pragma managed(push, off)
#endif

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved )
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
    return TRUE;
}

#ifdef _MANAGED
#pragma managed(pop)
#endif

#undef OLE2A
#define OLE2A(x) (x ? A2W(x) : "") 
#define IsEqualGUID(rguid1, rguid2) (!memcmp(rguid1, rguid2, sizeof(GUID))) 

const int TIMESTAMP_LEN = 256;

const char FILELOG[]      = "FILE";
const char XMLLOG[]       = "XML";
const char DBLOG[]        = "DATABASE";
const char OTHERLOG[]     = "OTHER";
const char RESERVEDLOG[]  = "RESERVED";

static CLoggingFactory * LOGFACTORY = NULL;
static CRegistryFacade LOGGING_REGISTRY("SOFTWARE\\Nielsen\\Logging");

std::ostream& operator<<(std::ostream& out, CEntry::SEVERITY& e)
{
  switch (e)
  {
  case CEntry::Info:
      out << "[" << 0 << "] Info";
      break;
    case CEntry::Debug:
      out << "[" << 1 << "] Debug";
      break;
    case CEntry::Warning:
      out << "[" << 2 << "] Warning";
      break;
    case CEntry::Critical:
      out << "[" << 3 << "] Critical";
      break;
    case CEntry::Error:
      out << "[" << 4 << "] Error";
      break;
  }
  return out;
}

std::ostream& CEntry::operator<<(std::ostream& out)
{
  out << "-------------------------------------------------------------------" << "\r\n"
      << "Log-Id:      " << "\t" << this->m_id << "\r\n"
      << "GUID:        " << "\t" << this->m_guid << "\r\n"
      << "Timestamp:   " << "\t" << this->m_ts << "\r\n"
      << "Severity:    " << "\t" << this->m_severity << "\r\n";

  if (NULL != this->m_desc)
    out << "Description: " << "\t" << this->m_desc << "\r\n";
  else
    out << "Description:  " << "\t" << "\r\n";

  if (NULL != this->m_stack)
    out << "StackTrace:  " << "\t" << this->m_stack << "\r\n";
  else
    out << "StackTrace:  " << "\t" << "\r\n";

  return out;
}

void tm2a(struct tm * time, char ** ppSz, bool bDateOnly = false)
{
  char s[TIMESTAMP_LEN];
  memset(s, 0, sizeof(s));

  char mday[16];
  if (10 > time->tm_mday)
    sprintf(mday, "0%d", time->tm_mday);
  else 
    sprintf(mday, "%d", time->tm_mday);

  char mon[16];
  if (10 > time->tm_mon)
    sprintf(mon, "0%d", time->tm_mon +1);
  else 
    sprintf(mon, "%d", time->tm_mon +1);

  char year[16];
  if (10 > time->tm_year)
    sprintf(year, "0%d", time->tm_year +1900);
  else 
    sprintf(year, "%d", time->tm_year +1900);

  char hour[16];
  if (10 > time->tm_hour)
    sprintf(hour, "0%d", time->tm_hour);
  else 
    sprintf(hour, "%d", time->tm_hour);

  char min[16];
  if (10 > time->tm_min)
    sprintf(min, "0%d", time->tm_min);
  else 
    sprintf(min, "%d", time->tm_min);

  char sec[16];
  if (10 > time->tm_sec)
    sprintf(sec, "0%d", time->tm_sec);
  else 
    sprintf(sec, "%d", time->tm_sec);

  if (bDateOnly)
    sprintf(s, "%s-%s-%s", year, mon, mday);
  else
    sprintf(s, "%s:%s:%s %s-%s-%s", hour, min, sec, year, mon, mday);
  
  *ppSz = new char[strlen(s) +1];
  memset(*ppSz, 0, strlen(s) +1);
  strncpy(*ppSz, s, strlen(s));
}

void tm2a(char ** ppSz, bool bDateOnly = false)
{
  struct tm *newtime;
  time_t long_time;
  time( &long_time );                
  newtime = localtime( &long_time ); 

  tm2a(newtime, ppSz, bDateOnly);
}

void write2file(const char *filename, const char *data)
{
  FILE * fp = fopen(filename, "wb");
  if (fp) {
    fwrite(data, 1, strlen(data), fp);
    fclose(fp);
  }
}

CEntry::CEntry()
{
  struct tm *newtime;
  time_t long_time;
  time( &long_time );                
  newtime = localtime( &long_time ); 

  tm2a(newtime, &m_ts);

  GUID g;
  CoCreateGuid (&g);
  OLECHAR sbuff[100];
  StringFromGUID2(g,sbuff,100);

  USES_CONVERSION; 
  memset(m_guid,0,sizeof(m_guid));  
  char * t = OLE2T(sbuff);
  strncpy(m_guid, t, strlen(t));

  m_id = 0;
  m_desc = NULL;
  m_severity = Info; 
  m_stack = NULL;
}

CEntry::CEntry(const char* descr)
{
  struct tm *newtime;
  time_t long_time;
  time( &long_time );                
  newtime = localtime( &long_time ); 

  tm2a(newtime, &m_ts);

  GUID g;
  CoCreateGuid (&g);
  OLECHAR sbuff[100];
  StringFromGUID2(g,sbuff,100);

  USES_CONVERSION; 
  memset(m_guid,0,sizeof(m_guid));  
  char * t = OLE2T(sbuff);
  strncpy(m_guid, t, strlen(t));

  m_id = 0;
  m_desc = new char[strlen(descr) +1];
  memset(m_desc, 0, strlen(descr) +1);
  strncpy(m_desc, descr, strlen(descr));
  m_severity = Debug; 
  m_stack = NULL;
}

CEntry::CEntry(SEVERITY sev, const char* descr)
{
  struct tm *newtime;
  time_t long_time;
  time( &long_time );                
  newtime = localtime( &long_time ); 

  tm2a(newtime, &m_ts);

  GUID g;
  CoCreateGuid (&g);
  OLECHAR sbuff[100];
  StringFromGUID2(g,sbuff,100);

  USES_CONVERSION; 
  memset(m_guid,0,sizeof(m_guid));  
  char * t = OLE2T(sbuff);
  strncpy(m_guid, t, strlen(t));

  m_id = 0;
  m_desc = new char[strlen(descr) +1];
  memset(m_desc, 0, strlen(descr) +1);
  strncpy(m_desc, descr, strlen(descr));
  m_severity = sev; 
  m_stack = NULL;
}

CEntry::~CEntry()
{
  if (NULL != m_desc) {
    delete[] m_desc;
    m_desc = NULL;
  }
  if (NULL != m_ts) {
    delete[] m_ts;
    m_ts = NULL;
  }
  if (NULL != m_stack) {
    delete[] m_stack;
    m_stack = NULL;
  }
}

const char * CEntry::getTimestamp() const
{
  return m_ts;
}

const int CEntry::getSeverity() const
{
  return m_severity;
}

const int CEntry::getId() const
{
  return m_id;
}

const char* CEntry::getGuid() const
{
  return m_guid;
}

const char* CEntry::getDescription() const
{
  return m_desc;
}

const char* CEntry::getStackTrace() const
{
  return m_stack;
}

void CEntry::setStackTrace(const char* text)
{
  if (NULL != m_stack) {
    delete[] m_stack;
    m_stack = NULL;
  }

  m_stack = new char[strlen(text) + 1];
  memset(m_stack, 0, strlen(text) + 1);
  strncpy(m_stack, text, strlen(text));
}

CLogger::CLogger()
{
  char * pszValue = NULL;
  LOGGING_REGISTRY.getKeyFromRegistry("LoggingLevel", &pszValue, "3");
  m_SevLevel = (CEntry::SEVERITY)atoi(pszValue);
  delete[] pszValue;

  tm2a(&m_szLogname);
  std::string s (m_szLogname);
  s = s.substr(9, 10);

  if (NULL != m_szLogname) {
    delete[] m_szLogname;
    m_szLogname = NULL;
  }

  m_szLogname = new char[strlen(s.c_str()) +1];
  memset(m_szLogname, 0, strlen(s.c_str()) +1);
  strncpy(m_szLogname, s.c_str(), strlen(s.c_str()));

  std::stringstream ss;
  ss << "[SOFTWARE\\Nielsen\\Logging]" << "\r\n"
     << "LoggingLevel    " << "\t" << m_szLogname << "\r\n"
     << "LoggingType     " << "\t" << FILELOG << "\r\n"
     << "\r\n"
     << "[SOFTWARE\\Nielsen\\Logging]" << "\r\n"
     << "LoggingLevel    " << "\t" << m_szLogname << "\r\n"
     << "LoggingType     " << "\t" << XMLLOG << "\r\n"
     << "\r\n"
     << "[SOFTWARE\\Nielsen\\Logging]" << "\r\n"
     << "LoggingLevel    " << "\t" << m_szLogname << "\r\n"
     << "LoggingType     " << "\t" << DBLOG << "\r\n";
  std::string str = ss.str();
  write2file("log-regvalues.txt", str.c_str());
}

CLogger::~CLogger()
{
  if (NULL != m_szLogname) {
    delete[] m_szLogname;
    m_szLogname = NULL;
  }
}

const char* CLogger::getLogName() const
{
  return m_szLogname;
} 

CLoggingFactory::CLoggingFactory()
{
  char * pszValue = NULL;
  LOGGING_REGISTRY.getKeyFromRegistry("LoggingType", &pszValue, FILELOG);

  m_szLogType = new char[strlen(pszValue) +1];
  memset(m_szLogType, 0, strlen(pszValue) +1);
  strncpy(m_szLogType, pszValue, strlen(pszValue));

  delete[] pszValue;
}

CLoggingFactory::~CLoggingFactory()
{
  if (NULL != m_szLogType) {
    delete[] m_szLogType;
    m_szLogType = NULL;
  }
}

const LogType CLoggingFactory::getLogtype() const
{
  if (!strcmp(m_szLogType, FILELOG))
    return eFile;
  else if (!strcmp(m_szLogType, XMLLOG))
    return eXml;
  else if (!strcmp(m_szLogType, DBLOG))
    return eDatabase;
  else if (!strcmp(m_szLogType, RESERVEDLOG))
    return eReserved;
  else
    return eOther;
}

